from php4dvd.model.user import User
from php4dvd.pages.internal_page import InternalPage
from php4dvd.pages.login_page import LoginPage
from php4dvd.pages.user_management_page import UserManagementPage
from php4dvd.pages.user_profile_page import UserProfilePage
from php4dvd.pages.add_new_movie_page import AddNewMoviePage
from php4dvd.pages.movie_info_page import MovieInfoPage
from php4dvd.pages.my_collection_page import MyCollectionPage
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support.expected_conditions import *
from selenium.webdriver.common.keys import Keys
import time

class any_window_other_than(object):
    def __init__(self, existing_windows):
        self.existing_windows = existing_windows

    def __call__(self, driver):
        handles = driver.window_handles
        diff = set(handles)-set(self.existing_windows)
        return iter(diff).next() if len(diff) > 0 else False

class Application(object):
    def __init__(self, driver, base_url, movie_name, movie_year):
        driver.get(base_url)
        self.wait = WebDriverWait(driver, 10)
        self.login_page = LoginPage(driver, base_url)
        self.internal_page = InternalPage(driver, base_url)
        self.user_profile_page = UserProfilePage(driver, base_url)
        self.user_management_page = UserManagementPage(driver, base_url)
        self.add_new_movie_page = AddNewMoviePage(driver,base_url)
        self.movie_info_page = MovieInfoPage(driver,base_url)
        self.my_collection_page = MyCollectionPage(driver,base_url)
        self.movie_name = movie_name
        self.movie_year = movie_year
        self.driver = driver

    def logout(self):
        self.internal_page.logout_button.click()
        self.wait.until(alert_is_present()).accept()

    def ensure_logout(self):
        element = self.wait.until(presence_of_element_located((By.CSS_SELECTOR, "nav, #loginform")))
        if element.tag_name == "nav":
            self.logout()

    def login(self, user):
        lp = self.login_page
        lp.is_this_page
        lp.username_field.send_keys(user.username)
        lp.password_field.send_keys(user.password)
        lp.submit_button.click()

    def ensure_login_as(self, user):
        element = self.wait.until(presence_of_element_located((By.CSS_SELECTOR, "nav, #loginform")))
        if element.tag_name == "nav":
            # we are on internal page
            if self.is_logged_in_as(user):
                return
            else:
                self.logout()
        self.login(user)

    def is_logged_in(self):
        return self.internal_page.is_this_page

    def is_logged_in_as(self, user):
        return self.is_logged_in() \
            and self.get_logged_user().username == user.username

    def is_not_logged_in(self):
        return self.login_page.is_this_page

    def get_logged_user(self):
        self.internal_page.user_profile_link.click()
        upp = self.user_profile_page
        upp.is_this_page
        return User(username=upp.user_form.username_field.get_attribute("value"),
                    email=upp.user_form.email_field.get_attribute("value"))

    def add_user(self, user):
        self.internal_page.user_management_link.click()
        ump = self.user_management_page
        ump.is_this_page
        ump.user_form.username_field.send_keys(user.username)
        ump.user_form.email_field.send_keys(user.email)
        ump.user_form.password_field.send_keys(user.password)
        ump.user_form.password1_field.send_keys(user.password)
        ump.user_form.submit_button.click()

    def open_my_collection_page(self):
        self.internal_page.home_link.click()

    def ensure_my_collection_page_open(self):
        if self.my_collection_page.is_this_page:
            return
        else:
            self.open_my_collection_page()

    def ensure_login_and_my_collection_page_open(self,user):
        if self.is_not_logged_in():
            self.login(user)
        else:
            self.ensure_my_collection_page_open()

    def add_trailer_url(self, page, title):
        original_window = self.driver.current_window_handle
        existing_windows = self.driver.window_handles
        page.trailer_url_button.click()
        new_window = self.wait.until(any_window_other_than(existing_windows))
        self.driver.switch_to_window(new_window)
        self.driver.find_element_by_id("masthead-search-term").send_keys(' ' + title)
        self.driver.find_element_by_id("search-btn").send_keys(Keys.RETURN)
        url = self.driver.find_element_by_id('search-results').find_element_by_xpath("./li[2]/div[2]/h3/a").get_attribute("href")
        self.driver.close()
        self.driver.switch_to_window(original_window)
        page.trailer_field.send_keys(url)

    def add_movie(self,movie):
        mcp = self.my_collection_page
        mcp.is_this_page
        mcp.add_movie_button.click()
        anmp = self.add_new_movie_page
        anmp.title_field.send_keys(movie.title)
        anmp.year_field.send_keys(movie.year)
        if movie.saw_movie_early:
            anmp.seen_yes_checkbox.click()
        else:
            anmp.seen_no_checkbox.click()
        self.add_trailer_url(anmp, movie.title)
        anmp.save_button.click()

    def is_movie_added(self, movie):
        return self.movie_info_page.is_this_page \
               and self.movie_info_page.movie_title.text == str(movie.title + ' (' + str(movie.year) + ')')

    def is_required_field_not_filled(self):
        return self.add_new_movie_page \
               and invisibility_of_element_located((By.CLASS_NAME, "error"))

    def is_year_filled_wrong(self):
        return self.add_new_movie_page \
               and self.add_new_movie_page.year_error.text == 'Please enter a valid number'

    def remove_first_movie(self):
        mcp = self.my_collection_page
        mcp.is_this_page
        mcp.search_for_movies_field.clear()
        mcp.search_for_movies_field.send_keys(Keys.RETURN)
        self.wait.until(lambda driver: mcp.is_this_page)
        time.sleep(2)
        current_count_of_movies_before = mcp.current_count_of_movies
        mcp.first_movie_link.click()
        mip = self.movie_info_page
        self.wait.until(lambda driver: mip.is_this_page)
        mip.remove_button.click()
        self.wait.until(alert_is_present())
        mip.alert.accept()
        self.wait.until(lambda driver: mcp.is_this_page)
        current_count_of_movies_after = mcp.current_count_of_movies
        if current_count_of_movies_after >= current_count_of_movies_before:
            raise Exception("Movie didn't delete %d >= %d" % (current_count_of_movies_after, current_count_of_movies_before))

    def search_movie(self, movie):
        mcp = self.my_collection_page
        mcp.is_this_page
        self.wait.until(lambda driver: mcp.is_this_page)
        mcp.search_for_movies_field.clear()
        mcp.search_for_movies_field.send_keys(movie.title)
        mcp.search_for_movies_field.send_keys(Keys.RETURN)
        time.sleep(2)

    def is_search_correct(self, movie):
        mcp = self.my_collection_page
        mcp.is_this_page
        self.wait.until(lambda driver: mcp.is_this_page)
        count_of_movies = mcp.current_count_of_movies
        if count_of_movies > 0:
            i=1
            while i < count_of_movies:
                if str(movie.title) not in \
                        self.driver.find_element_by_id("results").find_element_by_xpath("./a["+str(i)+"]").find_element_by_class_name('title').text:
                    return False
                i+=1
        else:
            raise Exception("There are no movies with title %s" % str(movie.title))
        return True

    def is_search_empty(self,movie):
        mcp = self.my_collection_page
        mcp.is_this_page
        self.wait.until(lambda driver: mcp.is_this_page)
        if mcp.empty_search_string.text == 'No movies where found.':
            return True
        else:
            return False

